package com.bootdo.app;

import cn.hutool.core.lang.Validator;
import com.bootdo.common.annotation.Log;
import com.bootdo.common.config.Constant;
import com.bootdo.common.controller.BaseController;
import com.bootdo.common.pojo.UserReq;
import com.bootdo.common.shiro.MobileToken;
import com.bootdo.common.utils.*;
import com.bootdo.system.domain.DeptDO;
import com.bootdo.system.domain.RoleDO;
import com.bootdo.system.domain.UserDO;
import com.bootdo.system.service.DeptService;
import com.bootdo.system.service.LoginService;
import com.bootdo.system.service.RoleService;
import com.bootdo.system.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Controller
@Slf4j
@RequestMapping("/app/")
public class AppLoginController extends BaseController {

    @Autowired
    private LoginService loginService;

    @Autowired
    private UserService userService;

    /**
     * 登录
     * @param req
     * @return
     */
    @PostMapping("/usernameLogin")
    @ResponseBody
    public R usernameLogin(UserReq req) {
        String username = req.getUsername();
        String password = req.getPassword();
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return R.error("用户名和密码不能为空！");
        }
        password = MD5Utils.encrypt(username, password);
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            UserDO userDO = (UserDO) subject.getPrincipal();
            if(userDO.getStatus() == 0) {
                return R.error("账号已被锁定,请联系管理员");
            }
            //登录生成token保存到redis中
            String jet_token = UuidUtils.getUUID();
            redisUtils.set(jet_token,userDO);
            Map<String,Object> map = new HashMap<String, Object>();
            map.put("token",jet_token);
            map.put("userDO",userDO);
            return R.ok(map);
        }catch (AuthenticationException e) {
            return R.error("用户或密码错误");
        }
    }

    /**
     * 注册(手机号跟用户名一样)
     * @param req
     * @return
     */
    @PostMapping("/register")
    @ResponseBody
    public R register(UserReq req) {
        String username = req.getMobile();
        req.setUsername(username);
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(req.getPassword())) {
            return R.error("用户名和密码不能为空！");
        }
        req.setPassword(MD5Utils.encrypt(username, req.getPassword()));
        if (!(Validator.isMobile(req.getMobile()))) {
            return R.error("手机号码格式错误，请重新填写！");
        }
        try {
            R result = checkCode(req.getMobile(), req.getCode());
            if (Objects.equals(result.get(R.CODE_KEY), Constant.ERROR_CODE)) {
                return result;
            }
            R r = loginService.register(req);
            if(!StringUtils.equals(String.valueOf(r.get("code")),"0")) {
                return r;
            }
            UserDO userDO = (UserDO) r.get("data");
            //登录生成token保存到redis中
            String jet_token = UuidUtils.getUUID();
            redisUtils.set(jet_token,userDO);
            Map<String,Object> map = new HashMap<String, Object>();
            map.put("token",jet_token);
            map.put("userDO",userDO);
            return R.ok(map);
        } catch (Exception e) {
            log.error("服务器内部错误：", e);
            return R.error("服务器繁忙，请稍后再试！");
        }
    }

    /**
     * 重置密码(手机号跟用户名一样)
     * @param req
     * @return
     */
    @PostMapping("/resetPassword")
    @ResponseBody
    public R resetPassword(UserReq req) {
        String mobile = req.getMobile();
        if (StringUtils.isEmpty(mobile) || StringUtils.isEmpty(req.getPassword())) {
            return R.error("用户名和密码不能为空！");
        }
        req.setPassword(MD5Utils.encrypt(mobile, req.getPassword()));
        if (!(Validator.isMobile(req.getMobile()))) {
            return R.error("手机号码格式错误，请重新填写！");
        }
        try {
            R result = checkCode(req.getMobile(), req.getCode());
            if (Objects.equals(result.get(R.CODE_KEY), Constant.ERROR_CODE)) {
                return result;
            }
            R r = loginService.resetPassword(req);
            return r;
        } catch (Exception e) {
            log.error("服务器内部错误：", e);
            return R.error("服务器繁忙，请稍后再试！");
        }
    }

    /**
     * 退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    @ResponseBody
    public R logout(HttpServletRequest request) {
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)) {
            return R.ok();
        }
        redisUtils.remove(token);
        return R.ok();
    }

    /**
     * 发送短信验证码
     * @param mobile
     * @return
     */
    @PostMapping("/sendVerifyCode")
    @ResponseBody
    public R sendVerifyCode(String mobile) {
        if (!(Validator.isMobile(mobile))) {
            return R.error("手机号码格式错误，请重新填写！");
        }
        R r = new R();
        try {
            r = loginService.sendVerifyCode(mobile);
        } catch (Exception e) {
            log.error("短信验证码发送异常:", e);
            return R.error("短信发送失败");
        }
        return r;
    }

    /**
     * 获取用户信息
     * @return
     */
    @PostMapping("/getUserDetail")
    @ResponseBody
    public R getUserDetail(UserDO userDO,HttpServletRequest request) {
        R r = checkToken(request);
        if(!StringUtils.equals(String.valueOf(r.get("code")),"0")) {
            return r;
        }
        userDO = userService.get(userDO.getUserId());
        return R.ok().put("userDO",userDO);
    }

    private R checkCode(String mobile, String code) throws Exception {
        String redisCode = (String) redisUtils.get(mobile);
        if (StringUtils.isEmpty(redisCode)) {
            return R.error("验证码无效或已过期，请重新发送！");
        }
        if (loginService.checkCodeUsed(mobile, code)) {
            return R.error("验证码已使用，请重新发送！");
        }
        return R.ok();
    }

}
